//
//  CCVector3.cpp
//  ShadowMapping
//
//  Created by Daniel Corleone on 13/6/14.
//  Copyright (c) 2014年 iCloverStudio. All rights reserved.
//

#ifndef __CC_VECTOR3_CCP__
#define __CC_VECTOR3_CCP__

#include "PlatformFeatures.h"
#include "CCVectors.h"
#include <cmath>

template<typename T>
Vector3<T>::Vector3()
    : x(0.0), y(0.0), z(0.0)
{
    /// empty
}

template <typename T>
Vector3<T>::Vector3(T _x, T _y, T _z)
    : x(_x), y(_y), z(_z)
{
    /// empty
}

template <typename T>
Vector3<T>::Vector3(const Vector3& otherV) : x(otherV.X), y(otherV.y), z(otherV.z) {
    /// empty
}

template<typename T>
Real
Vector3<T>::Length() const {
    Real sqareSum = x * x + y * y + z * z;
    return ::sqrt(sqareSum);
}

template<typename T>
Vector3<T>&
Vector3<T>::Normalize() {
    do {
        const Real length = this->Length();
        if (length < FLOAT_MIN) {
            break;
        }
        
        const Real InvSquare = 1.0 / length;
        x *= InvSquare;
        y *= InvSquare;
        z *= InvSquare;
        
    } while (false);
    return *this;
}

template<typename T>
Real
Vector3<T>::DotProduct(const Vector3<T> &other) const {
    return x * other.x + y * other.y;
}


template<typename T>
Vector3<T>
Vector3<T>::CrossProduct(const Vector3<T> &other) const {
    return Vector3<T>(Y * other.Z - Z * other.Y, Z * other.X - X * other.Z, X * other.Y - Y * other.X);
}


template <typename T>
Boolean Vector3<T>::Equal(const Vector3<T> &other, Real epsilon) {
    return (::fabs(x - other.x) < epsilon) && (::fabs(y - other.y) < epsilon) && (::fabs(z - other.z) < epsilon);
}

template <typename T>
Vector3<T> Vector3<T>::operator-() const {
    return Vector3<T>(-x, -y, -z);
}

template <typename T>
Vector3<T>
Vector3<T>::operator-(const Vector3<T>& other) const {
    return Vector3<T>(x - other.x, y - other.y, z - other.z);
}

template <typename T>
Vector3<T>
Vector3<T>::operator+(const Vector3<T>& other) const {
    return Vector3<T>(x + other.x, y + other.y, z + other.z);
}

template <typename T>
Vector3<T>&
Vector3<T>::operator-=(const Vector3<T>& other) {
    x -= other.x;
    y -= other.y;
    z -= other.z;
    return *this;
}

template <typename T>
Vector3<T>&
Vector3<T>::operator+=(const Vector3<T>& other) {
    x += other.x;
    y += other.y;
    z += other.z;
    return *this;
}

template <typename T>
Vector3<T>
Vector3<T>::operator*(const Real scale) const {
    return Vector3<T>(x * scale, y * scale, z * scale);
}

template <typename T>
Vector3<T>
Vector3<T>::operator*(const Vector3<T>& other) const {
    return Vector3<T>(x * other.x, y * other.y, z * other.z);
}

template <typename T>
Vector3<T>&
Vector3<T>::operator*=(const Real scale) {
    x *= scale; y *= scale; z *=scale;
    return *this;
}

template <typename T>
Vector3<T>&
Vector3<T>::operator*=(const Vector3<T>& other) {
    x *= other.x;
    y *= other.y;
    z *= other.z;
    return *this;
}

template <typename T>
Vector3<T>
Vector3<T>::operator/(const Real scale) const {
    return Vector3<T>(x / scale, y /scale, z/scale);
}

template <typename T>
Vector3<T>&
Vector3<T>::operator/= (const Real scale) {
    x /= scale;
    y /= scale;
    z /= scale;
    return *this;
}

template <typename T>
Boolean
Vector3<T>::operator==(const Vector3<T>& other) const {
    return (x == other.x && y == other.y && z == other.z);
}

template <typename T>
Boolean
Vector3<T>::operator!=(const Vector3<T>& other) const {
    return (x != other.x) && (y != other.y) && (z != other.z);
}

template<typename T>
void
Vector3<T>::Normalize(Vector3 &_otherV) {
    _otherV.Normalize();
    return;
}

template<typename T>
Real
Vector3<T>::DotProduct(const Vector3<T> &v1, const Vector3<T> &v2) {
    return v1.DotProduct(v2);
}

template<typename T>
Vector3<T>
Vector3<T>::CrossProduct(const Vector3<T> &v1, const Vector3<T> &v2) {
    return v1.CrossProduct(v2);
}

#endif  /// __CC_VECTOR3_CCP__

